#include "gtestex.h"
#include <fstream>
#include <istream>
using namespace gtestex;
using namespace gtestex::msg_transmit;

// Dependency injection
class TCPClientMock : public TCPClient {
 public:
  TCPClientMock() : TCPClient("127.0.1", "3490") { }
  
  virtual ~TCPClientMock() { }

  string& record() { return record_; }

 private:

  virtual int OSCloseConnection() { return 0; }

  virtual int OSOpenConnetion() { return 0; }

  virtual int OSSendMessage(const string& record, bool add_new_line) {
    record_ =  (add_new_line) ? (record + '\n') : record;

    return 0; 
  }
 
  string record_;
};

TEST(record_utility, Delimeter) {
  const string::value_type expected = ',';
  const string::value_type actual = record_utility::Delimeter();
  EXPECT_EQ(expected, actual);

}

TEST(record_utility, valid_record) {

}


TEST(record_utility, UrlEncode) {
  // Testing none
  {
    const char* cstring = "helloworld";
    const std::string& result = record_utility::UrlEncode(cstring);

    const char* actual = "helloworld";
    const char* expected = result.c_str();

    EXPECT_STRCASEEQ(expected, actual);
  }

   // Testing = -> %0x3D
  {
    namespace ru = record_utility;

    const char* cstring_with_equal = "hello=world";
    const std::string& result_equal = ru::UrlEncode(cstring_with_equal);

    const char* actual = "hello%3dworld";
    const char* expected = result_equal.c_str();

    EXPECT_STRCASEEQ(expected, actual);
  }
  
  // Testing & -> %0x26
  {
    namespace ru = record_utility;
    const char* cstring_with_ampersand = "hello&world";  
    const std::string& result_ampersand = ru::UrlEncode(cstring_with_ampersand);

    const char* actual = "hello%26world";
    const char* expected = result_ampersand.c_str();

    EXPECT_STRCASEEQ(expected, actual);
  }
  
  // Testing % -> %0x25
  {
    namespace ru = record_utility;
    const char* cstring_with_remainder = "hello%world";
    const std::string& result_remainder = ru::UrlEncode(cstring_with_remainder);

    const char* actual = "hello%25world";
    const char* expected = result_remainder.c_str();

    EXPECT_STRCASEEQ(expected, actual);
  }
  
  // Testing % -> %0x0A
  {
    namespace ru = record_utility;
    const char* cstring_with_new_line = "hello\nworld";
    const std::string& result_new_line = ru::UrlEncode(cstring_with_new_line);

    const char* actual = "hello%0aworld";
    const char* expected = result_new_line.c_str();

    EXPECT_STRCASEEQ(expected, actual);
  }
}

TEST(TCPSendMessageListenerClass, GetRecordId) {  
  const string msgerror1                       = "25";
  const string msgerror2                       = "-1";
  const string msgerror3                       = "string";
  const string msgkOnInvalidMemberFunction     = "0,";
  const string msgkOnTestProgramStart          = "1,";
  const string msgkOnTestIterationStart        = "2,";
  const string msgkOnEnvironmentsSetUpStart    = "3,";
  const string msgkOnEnvironmentsSetUpEnd      = "4,";
  const string msgkOnTestCaseStart             = "5,";
  const string msgkOnTestStart                 = "6,";
  const string msgkOnTestPartResult            = "7,";
  const string msgkOnTestEnd                   = "8,";
  const string msgkOnTestCaseEnd               = "9,";
  const string msgkOnEnvironmentsTearDownStart = "10,";
  const string msgkOnEnvironmentsTearDownEnd   = "11,";
  const string msgkOnTestIterationEnd          = "12,";
  const string msgkOnTestProgramEnd            = "13,";


  record_utility::RecordId e_msgerror1 = 
      record_utility::kOnInvalidMemberFunction;
  record_utility::RecordId a_msgerror1 = 
      record_utility::GetRecordId(msgerror1);
  EXPECT_EQ(e_msgerror1, a_msgerror1);

  record_utility::RecordId e_msgerror2 = 
      record_utility::kOnInvalidMemberFunction;
  record_utility::RecordId a_msgerror2 = 
      record_utility::GetRecordId(msgerror2);
  EXPECT_EQ(e_msgerror2, a_msgerror2);

  record_utility::RecordId e_msgerror3 = 
      record_utility::kOnInvalidMemberFunction;
  record_utility::RecordId a_msgerror3 = 
      record_utility::GetRecordId(msgerror3);
  EXPECT_EQ(e_msgerror3, a_msgerror3);

  record_utility::RecordId e_kOnTestProgramStart = 
      record_utility::kOnTestProgramStart;
  record_utility::RecordId a_kOnTestProgramStart = 
      record_utility::GetRecordId(msgkOnTestProgramStart);
  EXPECT_EQ(e_kOnTestProgramStart, a_kOnTestProgramStart);

  record_utility::RecordId e_msgkOnTestIterationStart = 
      record_utility::kOnTestIterationStart;
  record_utility::RecordId a_msgkOnTestIterationStart = 
      record_utility::GetRecordId(msgkOnTestIterationStart);
  EXPECT_EQ(e_msgkOnTestIterationStart, a_msgkOnTestIterationStart);

  record_utility::RecordId e_msgkOnEnvironmentsSetUpStart = 
      record_utility::kOnEnvironmentsSetUpStart;
  record_utility::RecordId a_msgkOnEnvironmentsSetUpStart = 
      record_utility::GetRecordId(msgkOnEnvironmentsSetUpStart);
  EXPECT_EQ(e_msgkOnEnvironmentsSetUpStart, a_msgkOnEnvironmentsSetUpStart);

  record_utility::RecordId e_msgkOnEnvironmentsSetUpEnd = 
      record_utility::kOnEnvironmentsSetUpEnd;
  record_utility::RecordId a_msgkOnEnvironmentsSetUpEnd = 
      record_utility::GetRecordId(msgkOnEnvironmentsSetUpEnd);
  EXPECT_EQ(e_msgkOnEnvironmentsSetUpEnd, a_msgkOnEnvironmentsSetUpEnd);

  record_utility::RecordId e_msgkOnTestCaseStart = 
      record_utility::kOnTestCaseStart;
  record_utility::RecordId a_msgkOnTestCaseStart = 
      record_utility::GetRecordId(msgkOnTestCaseStart);
  EXPECT_EQ(e_msgkOnTestCaseStart, a_msgkOnTestCaseStart);

  record_utility::RecordId e_msgkOnTestStart = 
      record_utility::kOnTestStart;
  record_utility::RecordId a_msgkOnTestStart = 
      record_utility::GetRecordId(msgkOnTestStart);
  EXPECT_EQ(e_msgkOnTestStart, a_msgkOnTestStart);

  record_utility::RecordId e_msgkOnTestPartResult = 
      record_utility::kOnTestPartResult;
  record_utility::RecordId a_msgkOnTestPartResult = 
      record_utility::GetRecordId(msgkOnTestPartResult);
  EXPECT_EQ(e_msgkOnTestPartResult, a_msgkOnTestPartResult);

  record_utility::RecordId e_msgkOnTestEnd = 
      record_utility::kOnTestEnd;
  record_utility::RecordId a_msgkOnTestEnd = 
      record_utility::GetRecordId(msgkOnTestEnd);
  EXPECT_EQ(e_msgkOnTestEnd, a_msgkOnTestEnd);

  record_utility::RecordId e_msgkOnTestCaseEnd = 
      record_utility::kOnTestCaseEnd;
  record_utility::RecordId a_msgkOnTestCaseEnd = 
      record_utility::GetRecordId(msgkOnTestCaseEnd);
  EXPECT_EQ(e_msgkOnTestCaseEnd, a_msgkOnTestCaseEnd);

  record_utility::RecordId e_msgkOnEnvironmentsTearDownStart = 
      record_utility::kOnEnvironmentsTearDownStart;
  record_utility::RecordId a_msgkOnEnvironmentsTearDownStart = 
      record_utility::GetRecordId(msgkOnEnvironmentsTearDownStart);
  EXPECT_EQ(e_msgkOnEnvironmentsTearDownStart, 
            a_msgkOnEnvironmentsTearDownStart);
  
  record_utility::RecordId e_msgkOnEnvironmentsTearDownEnd = 
      record_utility::kOnEnvironmentsTearDownEnd;
  record_utility::RecordId a_msgkOnEnvironmentsTearDownEnd = 
      record_utility::GetRecordId(msgkOnEnvironmentsTearDownEnd);
  EXPECT_EQ(e_msgkOnEnvironmentsTearDownEnd, a_msgkOnEnvironmentsTearDownEnd);

  record_utility::RecordId e_msgkOnTestIterationEnd = 
      record_utility::kOnTestIterationEnd;
  record_utility::RecordId a_msgkOnTestIterationEnd = 
      record_utility::GetRecordId(msgkOnTestIterationEnd);
  EXPECT_EQ(e_msgkOnTestIterationEnd, a_msgkOnTestIterationEnd);

  record_utility::RecordId e_msgkOnTestProgramEnd = 
      record_utility::kOnTestProgramEnd;
  record_utility::RecordId a_msgkOnTestProgramEnd = 
      record_utility::GetRecordId(msgkOnTestProgramEnd);
  EXPECT_EQ(e_msgkOnTestProgramEnd, a_msgkOnTestProgramEnd);

  record_utility::RecordId e_msgkOnInvalidMemberFunction = 
      record_utility::kOnInvalidMemberFunction;
  record_utility::RecordId a_msgkOnInvalidMemberFunction = 
      record_utility::GetRecordId(msgkOnInvalidMemberFunction);
  EXPECT_EQ(e_msgkOnInvalidMemberFunction, a_msgkOnInvalidMemberFunction);
}

TEST(TCPSendMessageListenerClass, OnTestProgramStart) {
  TCPClientMock* tcp_client_mock = new TCPClientMock;
  TCPSendRecordListener listener(tcp_client_mock);

  UnitTest* ut = UnitTest::GetInstance();
  listener.OnTestProgramStart(*ut);

  string& record = tcp_client_mock->record();

  record_utility::RecordId e_kOnTestProgramStart = 
      record_utility::kOnTestProgramStart;
  record_utility::RecordId a_kOnTestProgramStart = 
      record_utility::GetRecordId(record);
  EXPECT_EQ(e_kOnTestProgramStart, a_kOnTestProgramStart);
}

TEST(TCPSendMessageListenerClass, OnTestIterationStart) {
  TCPClientMock* tcp_client_mock = new TCPClientMock;
  TCPSendRecordListener listener(tcp_client_mock);

  UnitTest* ut = UnitTest::GetInstance();
  listener.OnTestIterationStart(*ut, 0);

  string& record = tcp_client_mock->record();

  record_utility::RecordId e_kOnTestIterationStart = 
      record_utility::kOnTestIterationStart;
  record_utility::RecordId a_kOnTestIterationStart = 
      record_utility::GetRecordId(record);
  EXPECT_EQ(e_kOnTestIterationStart, a_kOnTestIterationStart);
}

TEST(TCPSendMessageListenerClass, OnEnvironmentsSetUpStart) {
  TCPClientMock* tcp_client_mock = new TCPClientMock;
  TCPSendRecordListener listener(tcp_client_mock);

  UnitTest* ut = UnitTest::GetInstance();
  listener.OnEnvironmentsSetUpStart(*ut);

  string& record = tcp_client_mock->record();

  record_utility::RecordId e_kOnEnvironmentsSetUpStart = 
      record_utility::kOnEnvironmentsSetUpStart;
  record_utility::RecordId a_kOnEnvironmentsSetUpStart = 
      record_utility::GetRecordId(record);
  EXPECT_EQ(e_kOnEnvironmentsSetUpStart, a_kOnEnvironmentsSetUpStart);
}

TEST(TCPSendMessageListenerClass, OnEnvironmentsSetUpEnd) {
  TCPClientMock* tcp_client_mock = new TCPClientMock;
  TCPSendRecordListener listener(tcp_client_mock);

  UnitTest* ut = UnitTest::GetInstance();

  listener.OnEnvironmentsSetUpEnd(*ut);

  string& record = tcp_client_mock->record();

  record_utility::RecordId e_kOnEnvironmentsSetUpEnd = 
      record_utility::kOnEnvironmentsSetUpEnd;
  record_utility::RecordId a_kOnEnvironmentsSetUpEnd = 
      record_utility::GetRecordId(record);
  EXPECT_EQ(e_kOnEnvironmentsSetUpEnd, a_kOnEnvironmentsSetUpEnd);
}

TEST(TCPSendMessageListenerClass, OnTestCaseStart) {
  TCPClientMock* tcp_client_mock = new TCPClientMock;
  TCPSendRecordListener listener(tcp_client_mock);

  UnitTest* ut = UnitTest::GetInstance();
  const TestCase* tc = ut->current_test_case(); 
  listener.OnTestCaseStart(*tc);

  string& record = tcp_client_mock->record();

  record_utility::RecordId e_kOnTestCaseStart = 
      record_utility::kOnTestCaseStart;
  record_utility::RecordId a_kOnTestCaseStart = 
      record_utility::GetRecordId(record);
  EXPECT_EQ(e_kOnTestCaseStart, a_kOnTestCaseStart);
}

TEST(TCPSendMessageListenerClass, OnTestStart) {
  TCPClientMock* tcp_client_mock = new TCPClientMock;
  TCPSendRecordListener listener(tcp_client_mock);

  UnitTest* ut = UnitTest::GetInstance();
  const TestInfo* ti = ut->current_test_info();
  listener.OnTestStart(*ti);

  string& record = tcp_client_mock->record();
   
  record_utility::RecordId e_kOnTestStart = 
      record_utility::kOnTestStart;
  record_utility::RecordId a_kOnTestStart = 
      record_utility::GetRecordId(record);
  EXPECT_EQ(e_kOnTestStart, a_kOnTestStart);
}

TEST(TCPSendMessageListenerClass, OnTestPartResult) {
  TCPClientMock* tcp_client_mock = new TCPClientMock;
  TCPSendRecordListener listener(tcp_client_mock);

  const char* filename = "a_file";
  const int line_numer = 23;
  const char* msg  = "none";
  TestPartResult tr(TestPartResult::kSuccess, filename, line_numer, msg);

  listener.OnTestPartResult(tr);

  string& record = tcp_client_mock->record();

  record_utility::RecordId e_kOnTestPartResult = 
      record_utility::kOnTestPartResult;
  record_utility::RecordId a_kOnTestPartResult = 
      record_utility::GetRecordId(record);
  EXPECT_EQ(e_kOnTestPartResult, a_kOnTestPartResult);
}

TEST(TCPSendMessageListenerClass, OnTestEnd) {
  TCPClientMock* tcp_client_mock = new TCPClientMock;
  TCPSendRecordListener listener(tcp_client_mock);

  UnitTest* ut = UnitTest::GetInstance();
  const TestInfo* ti = ut->current_test_info();
  listener.OnTestEnd(*ti);

  string& record = tcp_client_mock->record();

  record_utility::RecordId e_kOnTestEnd = 
      record_utility::kOnTestEnd;
  record_utility::RecordId a_kOnTestEnd = 
      record_utility::GetRecordId(record);
  EXPECT_EQ(e_kOnTestEnd, a_kOnTestEnd);
}

TEST(TCPSendMessageListenerClass, OnTestCaseEnd) {
  TCPClientMock* tcp_client_mock = new TCPClientMock;
  TCPSendRecordListener listener(tcp_client_mock);
  UnitTest* ut = UnitTest::GetInstance();
  const TestCase* tc = ut->current_test_case();
  listener.OnTestCaseEnd(*tc);
  
  string& record = tcp_client_mock->record();

  record_utility::RecordId e_kOnTestCaseEnd = 
      record_utility::kOnTestCaseEnd;
  record_utility::RecordId a_kOnTestCaseEnd = 
      record_utility::GetRecordId(record);
  EXPECT_EQ(e_kOnTestCaseEnd, a_kOnTestCaseEnd);
}

TEST(TCPSendMessageListenerClass, OnEnvironmentsTearDownStart) {
  TCPClientMock* tcp_client_mock = new TCPClientMock;
  TCPSendRecordListener listener(tcp_client_mock);

  UnitTest* ut = UnitTest::GetInstance();
  listener.OnEnvironmentsTearDownStart(*ut);

  string& record = tcp_client_mock->record();

  record_utility::RecordId e_kOnEnvironmentsTearDownStart = 
      record_utility::kOnEnvironmentsTearDownStart;
  record_utility::RecordId a_kOnEnvironmentsTearDownStart = 
      record_utility::GetRecordId(record);
  EXPECT_EQ(e_kOnEnvironmentsTearDownStart, a_kOnEnvironmentsTearDownStart);
}

TEST(TCPSendMessageListenerClass, OnEnvironmentsTearDownEnd) {
  TCPClientMock* tcp_client_mock = new TCPClientMock;
  TCPSendRecordListener listener(tcp_client_mock);

  UnitTest* ut = UnitTest::GetInstance();
  listener.OnEnvironmentsTearDownEnd(*ut);

  string& record = tcp_client_mock->record();

  record_utility::RecordId e_kOnEnvironmentsTearDownEnd = 
      record_utility::kOnEnvironmentsTearDownEnd;
  record_utility::RecordId a_kOnEnvironmentsTearDownEnd = 
      record_utility::GetRecordId(record);
  EXPECT_EQ(e_kOnEnvironmentsTearDownEnd, a_kOnEnvironmentsTearDownEnd);
}

TEST(TCPSendMessageListenerClass, OnTestIterationEnd) {
  TCPClientMock* tcp_client_mock = new TCPClientMock;
  TCPSendRecordListener listener(tcp_client_mock);

  UnitTest* ut = UnitTest::GetInstance();
  listener.OnTestIterationEnd(*ut, 0);

  string& record = tcp_client_mock->record();

  record_utility::RecordId e_kOnTestIterationEnd =
      record_utility::kOnTestIterationEnd;
  record_utility::RecordId a_kOnTestIterationEnd =
      record_utility::GetRecordId(record);
  EXPECT_EQ(e_kOnTestIterationEnd, a_kOnTestIterationEnd);
}

TEST(TCPSendMessageListenerClass, OnTestProgramEnd) {
  TCPClientMock* tcp_client_mock = new TCPClientMock;
  TCPSendRecordListener listener(tcp_client_mock);

  UnitTest* ut = UnitTest::GetInstance();
  listener.OnTestProgramEnd(*ut);

  string& record = tcp_client_mock->record();
   
  record_utility::RecordId e_kOnTestProgramEnd =
      record_utility::kOnTestProgramEnd;
  record_utility::RecordId a_kOnTestProgramEnd =
      record_utility::GetRecordId(record);
  EXPECT_EQ(e_kOnTestProgramEnd, a_kOnTestProgramEnd);
}

TEST(records, unit_test) {
  TCPClientMock* tcp_client_mock = new TCPClientMock;
  TCPSendRecordListener listener(tcp_client_mock);

  UnitTest* ut = UnitTest::GetInstance();
  listener.OnTestProgramEnd(*ut);

  string& record = tcp_client_mock->record();

  record_utility::RecordId e_kOnTestProgramEnd =
      record_utility::kOnTestProgramEnd;
  record_utility::RecordId a_kOnTestProgramEnd =
      record_utility::GetRecordId(record);
  EXPECT_EQ(e_kOnTestProgramEnd, a_kOnTestProgramEnd);
}

TEST(records, IsRecordValidTest) {
  std::ifstream input_record_file("records.txt");
  if (input_record_file.is_open()) {
    std::string record; 
    while(input_record_file.good() && std::getline(input_record_file, record)) {
      EXPECT_TRUE(record_utility::IsRecordValid(record));
      record.clear();
    }
  }
  else { 
     assert(false);
  }
    

   //EXPECT_FALSE(record_utility::IsRecordValid("INVALID_STR"));

   //EXPECT_FALSE(record_utility::IsRecordValid("0"));

   //EXPECT_FALSE(record_utility::IsRecordValid("1"));

}
